// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: jhkim, junglekim

#pragma once

#include <fmt/core.h>
#include <glog/logging.h>
#include <google/protobuf/util/json_util.h>
#include <nlohmann/json.hpp>
#include <rapidjson/encodedstream.h>
#include "coin2/app/driver.h"
#include "coin2/strategy/order_executor/executor.h"
#include "coin2/strategy/order_executor.pb.h"
#include "coin2/strategy/order_executor/mm_executor.h"
#include "coin2/exchange/base/symbology/product_encyclopedia.h"


namespace coin2::strategy::cmm_strat {

using ::coin2::exchange::base::order::IOrderSubsystem;
using ::coin2::exchange::base::order::OrderUpdate;
using coin2::exchange::base::symbology::IProductInfo;
using coin2::exchange::base::symbology::IProduct;
using coin2::strategy::PassiveExecutorConfig;
using coin2::strategy::order_executor::PassiveOrderExecutor;
using OrderSpec = coin2::exchange::base::order::OrderSpec;
using coin::proto::OrderEvent;
using coin::proto::OrderSide;
using coin::proto::OrderType;
using coin::proto::TradeSide;
using coin::proto::OrderDuration;
using coin2::app::impl::Driver;

class CmmOrderController {
 public:
  CmmOrderController(
      const ::nlohmann::json& oc_config,
      std::optional<int64_t> ts,
      bool dry_run);

  void InitExecutor(
      PassiveExecutorConfig exe_config0,
      PassiveExecutorConfig exe_config1,
      IOrderSubsystem* os0,
      IOrderSubsystem* os1,
      Driver* driver);
  
  void SubmitAggOrder(int64_t ts, double pricer, double qty, OrderSide side);
  int TossRandomSide(void);
  int GenSide(double avg_period_min, double qty_1month, double imb_threshold);
  double GenRandomQty(double avg_period_min, double qty_1month, double range, const IProductInfo* pi_);
  
  void onCleanup0();
  void onCleanup1();
  void onFairPriceUpdate(double bid, double ask, int64_t timestamp_, const IProductInfo* pi_, const IProduct* product, Driver* driver);
  void onAccountInfo(const OrderUpdate& upd);
  void onAccountOrder(const OrderUpdate& upd);
  void ControlState();

  ::nlohmann::json& GetOcConfig() { return oc_config_; }
  PassiveOrderExecutor* GetExecutor0() { return executor0_.get(); }
  PassiveOrderExecutor* GetExecutor1() { return executor1_.get(); }

 private:
  ::nlohmann::json oc_config_;
  int64_t strategy_created_time_;
  std::shared_ptr<PassiveOrderExecutor> executor0_;
  std::shared_ptr<PassiveOrderExecutor> executor1_;
  bool dry_run_;
  bool is_pos0_ready_ {false};
  bool is_pos1_ready_ {false};
  bool is_in_time_limit_{true};
  bool is_agg_triggered_{false};
  double accept_wait_time_ms_;
  bool is_same_owner_{false};
  std::unique_ptr<boost::asio::deadline_timer> state_timer_;
  Driver* driver_;
};

}  // namespace coin2::strategy::cmm_strat
